#
# Copyright 2008-2010 Vadim Zhukov <persgray@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AGAVA COMPANY ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AGAVA COMPANY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of the AGAVA Company.


#######################################
# Save backups on a one-per-month basis

package RB::RotateScheme::Monthly;
use strict;

use RB::RotateScheme;
use RB::Util qw/daysInMonth formatAnyDate/;
our @ISA = qw/RB::RotateScheme/;

sub _makeKeepDecision($@) {
	my $this = shift;
	my $leftToFind = $this->{'_maxLeft'};
	my (%found, $m, $lastM);
	# Sort descending
	foreach my $date(@_) {
		$m = substr($date, 0, 6);
		if ($leftToFind > 0 || $lastM eq $m) {
			unless (exists $found{$m}) {
				$leftToFind--;
			}
			$found{$m} = $date;
			$lastM = $m;
		}
	}
	return values %found;
}

{ my ($LastRobinMDay, $LastRobinWDay) = (-1, 0);
sub _shouldUpdate($$$) {
	my ($this, $testDate, $hashSrc) = (shift, shift, shift);
	$testDate = substr($testDate, 0, 6);

	my ($testYear, $testMonth, $testMDay) = (int(substr($testDate, 0, 4)),
	    int(substr($testDate, 4, 2))-1, int(substr($testDate, 6, 2)));
	my $lastMDay = daysInMonth($testYear, $testMonth);

	my $startMDay = 1;
	my $at;
	if (($at = ${main::Config}->{'monthly_dump_at_mday'})) {
		if ($at eq 'hash') {
			$startMDay += chooseByHash($lastMDay);
		} elsif ($at eq 'round-robin') {
			$LastRobinMDay = -1 if $LastRobinMDay >= $lastMDay;
			$startMDay += ++$LastRobinMDay;
		} elsif ((my $dayNum = wdayByName($at)) != -1) {
			my $startWDay = calcWeekday($testYear, $testMonth, $startMDay);
			my $dd = $startMDay - $dayNum;
			$dd += 7 if $dd < 0;
			$startMDay += $dd;
		} else {
			# May be only a number, see RB::Profile
			$startMDay += $at-1;
			$startMDay = $lastMDay if $startMDay > $lastMDay;
		}
	} else {
		if ($at = ${main::Config}->{'monthly_dump_at_wday'}) {
			if ($at eq 'hash') {
				$startMDay += chooseByHash(7, $hashSrc);
			} elsif ($at eq 'round-robin') {
				$LastRobinWDay = 0 if $LastRobinWDay == 7;
				$startMDay += $LastRobinWDay++;
			} elsif ((my $dayNum = wdayByName($at)) != -1) {
				$startMDay += $dayNum;
			} else {
				# May be only a number, see RB::Profile
				$startMDay += $at;
			}
		}
		$startMDay +=
		    7 * (int(${main::Config}->{'monthly_dump_at_week'}) - 1);
		if ($lastMDay < $startMDay) {
			# Leave day-of-week untouched, and use last month's week
			$startMDay = $lastMDay - (7 - ($startMDay % 7));
		}
	}

	my ($start, $end);
	if ($startMDay <= $testMDay) {
		$start = formatAnyDate($testYear, $testMonth, $startMDay);
		my $dm = daysInMonth($testYear, $testMonth+1);
		my $endMDay = ($dm < $startMDay) ? $dm : $startMDay;
		$end = formatAnyDate($testYear, $testMonth+1, $endMDay);
	} else {
		$end = formatAnyDate($testYear, $testMonth, $startMDay);
		my $dm = daysInMonth($testYear, $testMonth-1);
		$startMDay = ($dm < $startMDay) ? $dm : $startMDay;
		$start = formatAnyDate($testYear, $testMonth, $startMDay);
	}
	
	return ($start, $end);
} }


1;
